from core import Subconstruct, ConstructError


class AdapterError(ConstructError):
    pass
class ValidatorError(AdapterError):
    pass
class PaddingError(AdapterError):
    pass


class Adapter(Subconstruct):
    __slots__ = []
    def _parse(self, stream, context):
        return self._decode(self.subcon._parse(stream, context), context)
    def _build(self, obj, stream, context):
        self.subcon._build(self._encode(obj, context), stream, context)
    def _encode(self, obj, context):
        return obj
    def _decode(self, obj, context):
        return obj

class Validator(Adapter):
    __slots__ = []
    def _encode(self, obj, context):
        if not self._validate(obj, context):
            raise ValidatorError(obj)
        return obj
    def _decode(self, obj, context):
        if not self._validate(obj, context):
            raise ValidatorError(obj)
        return obj
    def _validate(self, obj, context):
        raise NotImplementedError()

class OneOf(Validator):
    __slots__ = ["valids"]
    def __init__(self, subcon, valids):
        Validator.__init__(self, subcon)
        self.valids = valids
    def _validate(self, obj, context):
        return obj in self.valids

class NoneOf(Validator):
    __slots__ = ["invalids"]
    def __init__(self, subcon, invalids):
        Validator.__init__(self, subcon)
        self.invalids = invalids
    def _validate(self, obj, context):
        return obj not in self.invalids

class PaddingAdapter(Adapter):
    __slots__ = ["padchar", "strict"]
    def __init__(self, subcon, padchar = "\x00", strict = False):
        Adapter.__init__(self, subcon)
        self.padchar = padchar
        self.strict = strict
    def _encode(self, obj, context):
        return self._sizeof(context) * self.pattern
    def _decode(self, obj, context):
        if self.strict:
            expected = self._sizeof(context) * self.pattern
            if obj != expected:
                raise PaddingError("expected %r, found %r" % (expected, obj))
        return obj



























